﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using GogTasks.Properties;
using System.Drawing;
using Business.Entities;
using System.Diagnostics;

namespace GogTasks.UserControls
{
    public partial class CheckTaskControl : UserControl
    {
        #region Properties
        /// <summary>
        /// Set to true to disable all interactive function for all controls of this type (checking, unchecking)
        /// </summary>
        public static bool DisableAll = false;

        /// <summary>
        /// Font to use when rendering date information
        /// </summary>
        private static Font DateFont;

        private int IndentWidth = 30;
        public const string NonAlphaNumCharsRegex = "[ \\.,:;\\-\\(\\)!\\*]";

        private static Color DateForeColor = Color.FromArgb(255, 215, 77);
        private static string DueDateString = "Due: {0}";
        //private Image _offscreenBuffer;
        //private Graphics _offscreenGraphics;
        private int _initHeightThis;
        private int _initHeightTextControl;
        private int _previousWidth;
        
        public event EventHandler Selected;
        public event EventHandler CheckedChanged;

        private Task _task;
        public Task Task
        {
            get
            {
                return _task;
            }
        }

        private bool _isSelected;
        /// <summary>
        /// True if this control is selected. Renders differently
        /// </summary>
        public bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            set
            {
                if (value != _isSelected)
                {
                    _isSelected = value;
                    Refresh();
                }
            }
        }

        private bool _isRightJustified = false;
        private bool _isLocInited = false;
        private bool _checkBoxAtRight;
        public bool CheckBoxAtRight
        {
            get
            {
                return _checkBoxAtRight;
            }
            set
            {
                _checkBoxAtRight = value;
                Refresh();
            }
        }

        private bool _checked;
        public bool Checked
        {
            get { return _checked; }
            set
            {
                if (_checked != value) 
                {
                    _checked = value;
                    if (Parent != null && Visible)
                    {
                        Flash();
                        SetPic();
                        _task.completed = value;
                        if (CheckedChanged != null) CheckedChanged.Invoke(this, new EventArgs());
                    }
                }
            }
        }

        private int _flashCol;
        private int _flashInc;
        private int _flashTarget;
        private bool _isFlashing;

        public override string Text
        {
            get
            {
                return TextControl.Text;
            }
            set
            {
                TextControl.Text = value;
                SetSize();
            }
        }

        //public override Font Font
        //{
        //    get
        //    {
        //        return TextControl.Font;
        //    }
        //    set
        //    {
        //        TextControl.Font = value;
        //    }
        //}

        public override Color ForeColor
        {
            get
            {
                return TextControl.ForeColor;
            }
            set
            {
                TextControl.ForeColor = value;
            }
        }

        private Label _taskDateControl;

        #endregion

        public CheckTaskControl(Task task)
        {
            InitializeComponent();
            IndentWidth =(int) (IndentWidth * MobileContext.SizeFactor);

            _task = task;
            _initHeightThis = Height;
            _initHeightTextControl = TextControl.Height;
            _previousWidth = Width;
            if (CheckPictureBox.Height != 64 || MobileContext.Config.FontSize != FontSizeEnum.Large)
            {
                CheckPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
//                TextControl.MinHeight = CheckPictureBox.Height;
            }
            SetFontSizeAndHeight();
            TextControl.MinHeight = CheckPictureBox.Height;
            SetData(_task);
            SetPic();
            SetSize();
            TextControl.Visible = true;

            TextControl.MouseDown += new MouseEventHandler(TextControl_MouseDown);
            TextControl.MouseUp += new MouseEventHandler(TextControl_MouseUp);
            //TextControl.MouseMove += new MouseEventHandler(TextControl_MouseMove);
        }

        private void SetFontSizeAndHeight()
        {
            int oldHeight = CheckPictureBox.Height;
            int diff;
            if (MobileContext.Config.FontSize == FontSizeEnum.Medium)
            {
                CheckPictureBox.Height = CheckPictureBox.Height * 3 / 4;
                CheckPictureBox.Width = CheckPictureBox.Width * 3 /4;
                diff = oldHeight - CheckPictureBox.Height;
                TextControl.Height -= diff;
                Height -= diff;
                
                TextControl.Font = MobileContext.TextFontMedium;
                DateFont = MobileContext.DateFontMedium;
            }
            else if (MobileContext.Config.FontSize == FontSizeEnum.Small)
            {
                //CheckPictureBox.Height /=  2;
                //CheckPictureBox.Width /= 2;
                CheckPictureBox.Height = CheckPictureBox.Height * 2 / 3;
                CheckPictureBox.Width = CheckPictureBox.Width * 2 / 3;
                diff = oldHeight - CheckPictureBox.Height;
                TextControl.Height -= diff;
                Height -= diff;

                TextControl.Font = MobileContext.TextFontSmall;
                DateFont = MobileContext.DateFontSmall;
            }
            else
            {
                TextControl.Font = MobileContext.TextFontLarge;
                DateFont = MobileContext.DateFontLarge;
            }
        }

        private void SetData(Task task)
        {
            _isLocInited = false;
            Text = task.name;
            Checked = task.completed;

            // Task date
            if (task.TaskDate != DateTime.MinValue)
            {
                if (_taskDateControl == null)
                {
                    _taskDateControl = new Label();
                    _taskDateControl.Font = DateFont;
                    _taskDateControl.ForeColor = DateForeColor;
                    int x = TextControl.Location.X;
                    if (MobileContext.Config.FontSize == FontSizeEnum.Large) _taskDateControl.Height = (int)(44 * MobileContext.SizeFactor);
                    if (MobileContext.Config.FontSize == FontSizeEnum.Medium) _taskDateControl.Height = (int)(34 * MobileContext.SizeFactor);
                    if (MobileContext.Config.FontSize == FontSizeEnum.Small) _taskDateControl.Height = (int)(28 * MobileContext.SizeFactor);
                    Height += _taskDateControl.Height;
                    _taskDateControl.Width = Width - x;
                    _taskDateControl.Location = new Point(x, Height-_taskDateControl.Height);
                    _taskDateControl.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
                    Controls.Add(_taskDateControl);
                    _taskDateControl.BringToFront();
                }
                _taskDateControl.Text = GetDueDateString(task.TaskDate);
            }
            else if (_taskDateControl != null)
            {
                Controls.Remove(_taskDateControl);
                Height -= _taskDateControl.Height;
                _taskDateControl.Dispose();
                _taskDateControl = null;
            }
        }

        private string GetDueDateString(DateTime due)
        {
            int days = due.Subtract(DateTime.Today).Days;
            if (days == 0) return String.Format(DueDateString, "today");
            if (days == 1) return String.Format(DueDateString, "tomorrow");
            return String.Format(DueDateString, due.ToString("M"));
        }

        void TextControl_MouseUp(object sender, MouseEventArgs e)
        {
            if (DisableAll) return;
            var scrollControl = Parent.Parent;
            if (scrollControl != null)
            {
                if (scrollControl.Location.Y - _clickBeginY < ClickThreshold &&
                    scrollControl.Location.Y - _clickBeginY > 0 - ClickThreshold)
                {
                    IsSelected = !IsSelected;
                    OnSelected();
                }
            }
        }
        void TextControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (DisableAll) return;
            var scrollControl = Parent.Parent;
            _clickBeginY = scrollControl.Location.Y;
        }

        private const int ClickThreshold = 15;
        private void OnSelected()
        {
            if (Selected != null) Selected.Invoke(this, new EventArgs());
        }


        private int _clickBeginY;

        private void Flash()
        {
            if (!_isFlashing)
            {
                _isFlashing = true;
                _flashCol = 255;
                _flashInc = -30;
                _flashTarget = BackColor.R;
                FlashTimer.Enabled = true;
            }
        }

        private void FlashTimer_Tick(object sender, EventArgs e)
        {
            bool hit = false;
            if (_flashInc < 0 && _flashCol <= _flashTarget) hit = true;
            if (_flashInc > 0 && _flashCol >= _flashTarget) hit = true;
                
            if (hit)
            {
                _flashCol = _flashTarget;
                FlashTimer.Enabled = false;
                _isFlashing = false;
            }
            var col = Color.FromArgb(_flashCol, _flashCol, _flashCol);
            TextControl.BackColor = col;
            BackColor = col;

            _flashCol += _flashInc;
        }

        private void SetPic()
        {
            if (!IsSelected)
            {
                if (Checked) CheckPictureBox.Image = Resources.check_light_notrans_1;
                else CheckPictureBox.Image = Resources.check_light_notrans_0;
            }
            else
            {
                if (Checked) CheckPictureBox.Image = Resources.check_light_sel_notrans_1;
                else CheckPictureBox.Image = Resources.check_light_sel_notrans_0;
            }
        }

        private void CheckPictureBox_Click(object sender, EventArgs e)
        {
            if (DisableAll) return;
            ToggleCheck();
        }

        private void ToggleCheck()
        {
            Checked = !Checked;
            SetPic();
            OnSelected(); // This will cause any OTHER task to be deselected
        }

        private void CheckPictureBox_DoubleClick(object sender, EventArgs e)
        {
            if (DisableAll) return;
        }

        private void SetSize()
        {
            SetSize(false);
        }

        private void SetSize(bool force)
        {
            _isLocInited = false;
            if (!force && Parent == null) return;
            _previousWidth = Width;
            int textConWidth = Width - CheckPictureBox.Width;
            // Indent
            textConWidth -= IndentWidth * _task.IndentLevel;
            textConWidth -= TextMargin;
            // set width
            TextControl.Width = textConWidth;
            // Set height
            int topMargin = _initHeightThis - _initHeightTextControl;
            int newHeight = topMargin + TextControl.Height;
            if (_taskDateControl != null)
            {
                newHeight += _taskDateControl.Height;
            }
            Height = newHeight;
        }

        private void CheckTaskControl_Resize(object sender, EventArgs e)
        {
            if (_previousWidth != Width)
            {
                SetSize();
            }
        }

        private void CheckTaskControl_ParentChanged(object sender, EventArgs e)
        {
            SetSize();
        }

        private void TextControl_TextChanged(object sender, EventArgs e)
        {
        }

        public override void Refresh()
        {
            //Trace.WriteLine("Refresh CTRL " + _task);
            SetControlLocations();
            SetBgCol();
            SetPic();
            base.Refresh();
        }

        private void SetBgCol()
        {
            var selCol = Color.FromArgb(60,60,60);
            var noSel = Color.Black;
            if  (_isSelected)
            {
                TextControl.BackColor = selCol;
                BackColor = selCol;
            }
            else
            {
                TextControl.BackColor = noSel;
                BackColor = noSel;
            }
        }

        private int TextMargin = 8;
        private void SetControlLocations()
        {
            if (_checkBoxAtRight && (!_isRightJustified || !_isLocInited))
            {
                // Move to right
                int picX = Width - CheckPictureBox.Width;
                int tbX = TextMargin;
                tbX += IndentWidth * _task.IndentLevel;
                CheckPictureBox.Location = new Point(picX, CheckPictureBox.Location.Y);
                TextControl.Location= new Point(tbX, TextControl.Location.Y);
                if (_taskDateControl != null) _taskDateControl.Left = tbX;
                _isRightJustified = true;
            }
            else if (!_checkBoxAtRight && (_isRightJustified ||  !_isLocInited))
            {
                // Move to left
                int picX = 0;
                int tbX = CheckPictureBox.Width;
                tbX += IndentWidth * _task.IndentLevel;
                picX += IndentWidth * _task.IndentLevel;
                CheckPictureBox.Location = new Point(picX, CheckPictureBox.Location.Y);
                TextControl.Location = new Point(tbX, TextControl.Location.Y);
                if (_taskDateControl != null) _taskDateControl.Left = tbX;
                _isRightJustified = false;
            }
            _isLocInited = true;
        }

       

        private void TextControl_Validated(object sender, EventArgs e)
        {
            TextControl.Text = TextControl.Text.Trim();
            SetSize();
            // Refresh parent (move controls up or down if size has changed)
            Control p = Parent;
            while (p != null)
            {
                if (p.Parent == null) p.Refresh(); // Topmost node
                p = p.Parent;
            }
        }

        /// <summary>
        /// Calulactes and sets height as needed 
        /// </summary>
        public void SetHeight()
        {
            TextControl.SuspendRendering = true;
            SetSize(true);
            TextControl.SetHeight();
            TextControl.SuspendRendering = false;
        }

        /// <summary>
        /// Call this if the underlying data has changed
        /// </summary>
        public void UpdateData()
        {
            SetData(_task);
            SetPic();
            SetSize(true);
        }

        public override string ToString()
        {
            return _task.ToString();
        }

    }
}
